package com.itzxx.huazhun.utils.ble

import android.util.Log
import com.jc.bledemo.SamplingRecordBean
import org.json.JSONObject
import java.math.BigInteger
import java.nio.ByteBuffer

const val BleDataHandler = "BleDataHandler"

@OptIn(ExperimentalUnsignedTypes::class)
fun dataVerification(data: UByteArray): Boolean {
    // 校验协议头
    if (data[0] != BleConstant.PROTOCOL_HEADER1) {
        Log.e(BleDataHandler, "header error")
        return false
    }
    if (data[1] != BleConstant.PROTOCOL_HEADER2) {
        Log.e(BleDataHandler, "header error")
        return false
    }
    // 校验结束符
    if (data[data.size - 2] != BleConstant.PROTOCOL_END1) {
        Log.e(BleDataHandler, "end error")
        return false
    }
    if (data[data.size - 1] != BleConstant.PROTOCOL_END2) {
        Log.e(BleDataHandler, "end error")
        return false
    }
    // 校验数据长度
    val dataLength = data[3].toInt()
    val originDataLength = data.size - 7// 7:head2 cmd1 data_len1 crc1 end2
    if (dataLength != originDataLength) {
        Log.e(BleDataHandler, "data length error")
        return false
    }
    // 校验数据
    val crc = getCRC(data)
    val data1 = data.dropLast(3)
    val originCrc = generateCRC(data1.toMutableList())
    if (crc != originCrc.toInt()) {
        Log.e(BleDataHandler, "data error")
        return false
    }
    return true
}


@OptIn(ExperimentalUnsignedTypes::class)
fun dataHeaderVerification(data: UByteArray): Boolean {
    // 校验协议头
    if (data[0] != BleConstant.PROTOCOL_HEADER1) {
        Log.e(BleDataHandler, "header error")
        return false
    }
    if (data[1] != BleConstant.PROTOCOL_HEADER2) {
        Log.e(BleDataHandler, "header error")
        return false
    }
    return true
}

@OptIn(ExperimentalUnsignedTypes::class)
fun dataEndVerification(data: UByteArray): Boolean {
    // 校验结束符
    if (data[data.size - 2] != BleConstant.PROTOCOL_END1) {
        Log.e(BleDataHandler, "end error")
        return false
    }
    if (data[data.size - 1] != BleConstant.PROTOCOL_END2) {
        Log.e(BleDataHandler, "end error")
        return false
    }
    return true
}


@OptIn(ExperimentalUnsignedTypes::class)
fun getCRC(data: UByteArray): Int {
    return data[data.size - 3].toInt()
}

fun generateCRC(data: MutableList<UByte>): UByte {
    var crc = 0
    for (i in 0..<data.size) {
        crc += data[i].toInt()
    }
    crc = crc.and(0xFF)
    return crc.toUByte()
}


@OptIn(ExperimentalUnsignedTypes::class)
fun getCmd(data: UByteArray): UByte {
    return data[2]
}

@OptIn(ExperimentalUnsignedTypes::class, ExperimentalStdlibApi::class)
fun getModel(data: UByteArray, start: Int, byteCount: Int): String {
    val sb = StringBuffer()
    for (i in 0..<byteCount) {
        val hexString = data[start + i].toHexString(HexFormat.UpperCase)
        if (hexString != "00") {
            sb.append(data[start + i].toInt().toChar())
        }
    }
    return sb.toString().trim()
}

@OptIn(ExperimentalUnsignedTypes::class, ExperimentalStdlibApi::class)
fun getMac(data: UByteArray, start: Int, byteCount: Int): String {
    val sb = StringBuffer()
    for (i in 0..<byteCount) {
        sb.append(data[start + i].toHexString(HexFormat.UpperCase)).append(":")
    }
    return sb.toString().trim().dropLast(1)
}

@OptIn(ExperimentalUnsignedTypes::class)
fun getHoleIndex(data: UByteArray, start: Int, probeCount: Int): String {
    val bs = if (probeCount > 0) {
        data[start].toInt().toString()
    } else {
        "0"
    }
    return if (bs.length < BleConstant.HOLE_NUM_MAX) {
        "0".repeat(BleConstant.HOLE_NUM_MAX - bs.length) + bs // 如果长度小于2，则补零到达2位
    } else {
        bs.substring(bs.length - 2) // 否则只保留最后2位
    }
}


@OptIn(ExperimentalUnsignedTypes::class, ExperimentalStdlibApi::class)
fun getProbes(
    data: UByteArray,
    start: Int,
    byteCount: Int,
    probeCount: Int,
): MutableList<String> {
    val list = mutableListOf<String>()
    if (probeCount > 0) {
        for (i in 0..<probeCount) {
            val jsonStr =JSONObject ()
            jsonStr.put("holeIndex", getHoleIndex(data, start + i + (i * byteCount), 1))
            jsonStr.put("probeMac", getMac(data, start + i + 1 + (i * byteCount), byteCount))
            list.add(jsonStr.toString())
        }
    }
    return list
}

@OptIn(ExperimentalUnsignedTypes::class)
fun getWayIndex(data: UByteArray, start: Int, wayNum: Int): MutableList<UByte> {
    val list = mutableListOf<UByte>()
    if (wayNum > 0) {
        for (i in start..<start + wayNum) {
            list.add(data[i])
        }
    }
    return list
}


@OptIn(ExperimentalUnsignedTypes::class)
fun getSamplingInfo(
    data: UByteArray,
    start: Int,
    byteCount: Int,
    readSize: Int,
): MutableList<SamplingInfoBean> {
    val list = mutableListOf<SamplingInfoBean>()
    for (i in 0..<readSize) {
        val newStart = start + (i * byteCount)
        val infoBean =
            handleSamplingInfo(data.copyOfRange(newStart, newStart + byteCount))
        list.add(infoBean)
    }
    return list
}

@OptIn(ExperimentalUnsignedTypes::class)
fun handleSamplingInfo(data: UByteArray): SamplingInfoBean {
    return SamplingInfoBean(
        recordStartTime = byteArray2Long(data.copyOfRange(0, 4).toByteArray()),
        recordSamplingInterval = byteArray2Long(data.copyOfRange(4, 8).toByteArray()) * 100 / 1000,
        recordStartIndex = byteArray2Long(data.copyOfRange(8, 12).toByteArray()),
        recordNum = byteArray2Long(data.copyOfRange(12, 16).toByteArray()),
    )
}

@OptIn(ExperimentalUnsignedTypes::class)
fun getRecordData(
    data: UByteArray,
    start: Int,
//    wayNum: Int,
//    wayIndex: MutableList<UByte>,
    readNum: Int,
): MutableList<SamplingRecordBean> {
    var array: UByteArray
    var  wayNum:Int
    try {
        wayNum = 2
        array = data.copyOfRange(start, start + readNum * (wayNum * 2))
    } catch (e: Exception) {
        wayNum = 1
        array = data.copyOfRange(start, start + readNum * (wayNum * 2))
    }
    val list = mutableListOf<SamplingRecordBean>()
    if (wayNum == 1) { // 单温
        for (i in array.indices step 2) {
            list.add(
                SamplingRecordBean(
                    temperature = byteArray2Int(array.copyOfRange(i, i + 2).toByteArray())
                )
            )
        }
    } else if (wayNum == 2) { // 气温
        for (i in array.indices step 4) {
            list.add(
                SamplingRecordBean(
                    airPressure = byteArray2Int(array.copyOfRange(i, i + 2).toByteArray()),
                    temperature = byteArray2Int(array.copyOfRange(i + 2, i + 4).toByteArray())
                )
            )
        }
    }
    return list
}

@OptIn(ExperimentalUnsignedTypes::class)
fun handleCommonResponse(data: UByteArray, tag: String) : String{
    val mac = getMac(data, 4, BleConstant.MAC_BYTE)
    val ack = data[12].toInt()
    val info = """
            mac : $mac
            ack : $ack -> ${if (ack == BleConstant.Ack.SUCCESS) "SUCCESS" else "ERROR"}
        """.trimIndent()
    val jsonStr =JSONObject ()
    jsonStr.put("mac", mac)
    jsonStr.put("ack", if (ack == BleConstant.Ack.SUCCESS) "SUCCESS" else "ERROR")
//    Log.e(tag, info)
    return jsonStr.toString()
}

@OptIn(ExperimentalUnsignedTypes::class)
fun int2uByteArray(num: Int, capacity: Int): UByteArray {
    val bytes = ByteBuffer.allocate(capacity).putInt(num)
    return bytes.array().toUByteArray()
}

@OptIn(ExperimentalUnsignedTypes::class)
fun long2uByteArray(num: Int, capacity: Int): UByteArray {
    val bytes = ByteBuffer.allocate(capacity).putInt(num)
    return bytes.array().toUByteArray()
}

fun byteArray2Int(array: ByteArray): Int {
    return BigInteger(array).toInt()
}

fun byteArray2Long(array: ByteArray): Long {
    return BigInteger(array).toLong()
}
